﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SoundEngine3;
using SoundEngine3.MIDI.Meta;

namespace ZquenceStudio3Host.DspPlugins.Synthesizers.Nodesizer.Engine.Modules.Converters
{
    [ModuleDisplay("Midi To Freq")]
    public class MidiConverterModule : BaseModule
    {
        private MidiMessageToWave mMidiToWave;

        int mPreviousNoteCount = 0;
        double mPreviousVelocity = 0;
        double mPreviousFrequency = 0;
        double mPreviousPitch = 0;

        public readonly ModuleInput MidiIn;

        public readonly ModuleOutput VelocityOut;
        public readonly ModuleOutput NoteFrequencyOut;
        public readonly ModuleOutput NotePitchOut;
        public readonly ModuleOutput MidiOut;

        public MidiConverterModule(ModuleManager manager)
            : base(manager)
        {
            mMidiToWave = new MidiMessageToWave(manager.SoundEngineContext);

            AddInput(MidiIn = new ModuleInput("Midi in", IOType.Midi, this));
            AddOutput(VelocityOut = new ModuleOutput("Velocity out", IOType.Audio, this));
            AddOutput(NoteFrequencyOut = new ModuleOutput("Frequency", IOType.Audio, this));
            AddOutput(NotePitchOut = new ModuleOutput("Pitch", IOType.Audio, this));
            AddOutput(MidiOut = new ModuleOutput("Midi out", IOType.Midi, this));
        }

        public override void Process()
        {
            if (MidiIn.IsConnected)
            {
                // Midi process.
                mMidiToWave.ProcessBegin(MidiIn.FromOutput.MidiBuffer);

                if (MidiOut.IsConnected)
                {
                    MidiOut.MidiBuffer.AddRange(MidiIn.FromOutput.MidiBuffer);
                }

                mPreviousNoteCount = mMidiToWave.Count;

                if (VelocityOut.IsConnected)
                {
                    //Array.Clear(VelocityOut.AudioBuffer, 0, VelocityOut.AudioBuffer.Length);
                    VelocityOut.AudioBuffer.Clear();

                    // Loop all ongoing midi notes.
                    for (int i = 0; i < mMidiToWave.Count; i++)
                    {
                        MidiMessageToWave.RunningNote note = mMidiToWave[i];

                        // Loop velocity out buffer an set values.
                        int start = (int)note.DeltaFrameOn;
                        //note.DeltaFrameOn = 0;

                        mPreviousVelocity = note.Velocity * 0.0039215686274509803921568627451;
                        for (int s = start; s < SoundEngineContext.BufferSize; s++)
                        {
                            VelocityOut.AudioBuffer[s] = mPreviousVelocity;
                        }

                        //mMidiToWave[i] = note;
                    }
                    if (mMidiToWave.Count == 0)
                    {
                        for (int s = 0; s < SoundEngineContext.BufferSize; s++)
                        {
                            VelocityOut.AudioBuffer[s] = mPreviousVelocity;
                        }
                    }
                }

                if (NoteFrequencyOut.IsConnected)
                {
                    //Array.Clear(NoteFrequencyOut.AudioBuffer, 0, NoteFrequencyOut.AudioBuffer.Length);
                    NoteFrequencyOut.AudioBuffer.Clear();

                    // Loop all ongoing midi notes.
                    for (int i = 0; i < mMidiToWave.Count; i++)
                    {
                        MidiMessageToWave.RunningNote note = mMidiToWave[i];

                        // Loop velocity out buffer an set values.
                        int start = (int)note.DeltaFrameOn;

                        mPreviousFrequency = SoundMath.FLKeyNoteC0 * SoundMath.Pow_Note(note.NoteKey);
                        for (int s = start; s < SoundEngineContext.BufferSize; s++)
                        {
                            NoteFrequencyOut.AudioBuffer[s] = mPreviousFrequency;
                        }
                    }
                    if (mMidiToWave.Count == 0)
                    {
                        for (int s = 0; s < SoundEngineContext.BufferSize; s++)
                        {
                            NoteFrequencyOut.AudioBuffer[s] = mPreviousFrequency;
                        }
                    }
                }
                
                if (NotePitchOut.IsConnected)
                {
                    //Array.Clear(NotePitchOut.AudioBuffer, 0, NotePitchOut.AudioBuffer.Length);
                    NoteFrequencyOut.AudioBuffer.Clear();

                    // Loop all ongoing midi notes.
                    for (int i = 0; i < mMidiToWave.Count; i++)
                    {
                        MidiMessageToWave.RunningNote note = mMidiToWave[i];

                        // Loop velocity out buffer an set values.
                        int start = (int)note.DeltaFrameOn;
                        //note.DeltaFrameOn = 0;

                        mPreviousPitch = note.NoteKey;
                        for (int s = start; s < SoundEngineContext.BufferSize; s++)
                        {
                            NotePitchOut.AudioBuffer[s] = mPreviousPitch;
                        }
                    }
                    if (mMidiToWave.Count == 0)
                    {
                        for (int s = 0; s < SoundEngineContext.BufferSize; s++)
                        {
                            NotePitchOut.AudioBuffer[s] = mPreviousPitch;
                        }
                    }
                }

                mMidiToWave.ProcessEnd();
            }
        }
    }
}
